package cn.sylinx.horm.core;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import cn.sylinx.horm.core.common.Callable;
import cn.sylinx.horm.core.common.Page;
import cn.sylinx.horm.core.common.Record;
import cn.sylinx.horm.dialect.Dialect;
import cn.sylinx.horm.resource.ClasspathSqlResource;
import cn.sylinx.horm.resource.parse.SqlParser;
import cn.sylinx.horm.transaction.jdbc.TransactionSupport;
import cn.sylinx.horm.util.Pair;

public interface SqlClient extends FluentSqlClient {

    static SqlClient getDefaultClient() {
        return getClientBy(null);
    }

    static SqlClient getClientBy(String dsName) {
        return DynamicClient.get(dsName);
    }

    /**
     * 解析sql
     * @param sqlResource
     * @param params
     * @return
     */
    Pair parseSql(ClasspathSqlResource sqlResource, Map<String, Object> params);

    /**
     * 解析sql
     * @param statement
     * @param type
     * @param params
     * @return
     */
    Pair parseSql(String statement, String type, Map<String, Object> params);

    /**
     * 获取事务支持
     *
     * @return
     */
    TransactionSupport getTransactionSupport();

    // for sql client begin

    /**
     * 获取数据源
     *
     * @return
     */
    String getDataSourceName();

    /**
     * 插入
     *
     * @param insertSql
     * @param params
     * @return
     * @throws SQLException
     */
    int insert(final String insertSql, final Object... params) throws SQLException;

    /**
     * 批量插入
     *
     * @param insertSqlTemplate
     * @param batchParams
     * @return
     * @throws SQLException
     */
    int[] insertBatch(final String insertSqlTemplate, final List<Object[]> batchParams) throws SQLException;

    /**
     * 删除
     *
     * @param deleteSql
     * @param params
     * @return
     * @throws SQLException
     */
    int delete(final String deleteSql, final Object... params) throws SQLException;

    /**
     * 更新
     *
     * @param updateSql
     * @param params
     * @return
     * @throws SQLException
     */
    int update(final String updateSql, final Object... params) throws SQLException;

    /**
     * 插入，返回主键
     *
     * @param insertSql
     * @param params
     * @return
     * @throws SQLException
     */
    Object insertForRetrieval(final String insertSql, final Object... params) throws SQLException;

    /**
     * Executes the SQL statement in this PreparedStatement object, which may be any
     * kind of SQL statement. Some prepared statements return multiple results; the
     * execute method handles these complex statements as well as the simpler form
     * of statements handled by the methods executeQuery and executeUpdate.
     * <p>
     * The execute method returns a boolean to indicate the form of the first
     * result. You must call either the method getResultSet or getUpdateCount to
     * retrieve the result; you must call getMoreResults to move to any subsequent
     * result(s).
     *
     * @param exeSql
     * @param params
     * @return
     * @throws SQLException
     */
    boolean execute(final String exeSql, final Object... params) throws SQLException;

    /**
     * 查询
     *
     * @param querySql
     * @param params
     * @return
     * @throws SQLException
     */
    List<Object[]> query(final String querySql, final Object... params) throws SQLException;

    /**
     * 查询单列
     *
     * @param querySql
     * @param params
     * @return
     * @throws SQLException
     */
    List<Object> queryForSingleColumn(final String querySql, final Object... params) throws SQLException;

    /**
     * 自定义操作
     *
     * @param <T>
     * @param callable
     * @return
     * @throws SQLException
     */
    <T> T call(Callable<T> callable) throws SQLException;
    // for sql client end

    // for orm client begin
    Dialect getDialect();

    SqlParser getSqlParser();

    <T> Serializable save(T t);

    <T> int insert(T t);

    <T> int[] insertBatch(List<T> t);

    Serializable insertForRetrieval(ClasspathSqlResource sqlResource, Map<String, Object> params);

    <T> int delete(T t);

    <T> int update(T t);

    int update(ClasspathSqlResource sqlResource, Map<String, Object> params);

    boolean execute(ClasspathSqlResource sqlResource, Map<String, Object> params);

    <T> T get(Serializable id, Class<T> modelClass);

    Page<Record> queryPage(String sql, int pageNumber, int pageSize, Object[] params);

    Page<Record> queryPage(ClasspathSqlResource sqlResource, int pageNumber, int pageSize,
                           Map<String, Object> params);

    <T> Page<T> queryPage(String sql, int pageNumber, int pageSize, Object[] params, Class<T> clz);

    <T> Page<T> queryPage(ClasspathSqlResource sqlResource, int pageNumber, int pageSize,
                          Map<String, Object> params, Class<T> clz);

    <R> Page<R> queryPageForSingleColumn(String sql, int pageNumber, int pageSize, Object[] params,
                                         Class<R> clz);

    Record queryRecord(String querySql, Object... params);

    List<Record> queryRecords(String querySql, Object... params);

    <T> List<T> queryList(Class<T> modelClass);

    <T> T queryFirst(final String querySql, final Object[] params, Class<T> modelClass);

    <T> List<T> queryList(final String querySql, final Object[] params, Class<T> modelClass);

    <T> T queryFirstForSingleColumn(ClasspathSqlResource sqlResource, Map<String, Object> params,
                                    Class<T> modelClass);

    <T> List<T> queryListForSingleColumn(ClasspathSqlResource sqlResource, Map<String, Object> params,
                                         Class<T> modelClass);

    <T> T queryFirstForSingleColumn(final String querySql, final Object[] params, Class<T> modelClass);

    <T> List<T> queryListForSingleColumn(final String querySql, final Object[] params, Class<T> modelClass);

    <T> T queryFirst(ClasspathSqlResource sqlResource, Map<String, Object> params, Class<T> modelClass);

    <T> List<T> queryList(ClasspathSqlResource sqlResource, Map<String, Object> params, Class<T> modelClass);

    Record queryRecord(ClasspathSqlResource sqlResource, Map<String, Object> params);

    List<Record> queryRecords(ClasspathSqlResource sqlResource, Map<String, Object> params);
    // for orm client end
}